package core

import (
	"fmt"
	"log"
	"net"
	"strconv"
	"time"
)

// Server UDP
type UDPServer struct {
	Name string
	Host string
	Port int
	l    *net.UDPConn
	Addr *net.UDPAddr
}

var s0 *UDPServer

func InitUDPServer(host string, port int) {
	s0 = newUDPServer(host, port)
	s0.start()
}

func GetUDPServer() *UDPServer {
	return s0
}

func newUDPServer(host string, port int) (s *UDPServer) {
	s = &UDPServer{
		host + ":" + strconv.Itoa(port),
		host,
		port,
		nil,
		nil,
	}
	return
}

func (s *UDPServer) start() error {
	addr, err := net.ResolveUDPAddr("udp", s.Host+":"+strconv.Itoa(s.Port))
	if err != nil {
		return err
	}
	s.Addr = addr

	l, err := net.ListenUDP("udp", addr)
	if err != nil {
		return err
	}
	s.l = l
	go s.read()

	log.Println(s.Name + " udp start port " + strconv.Itoa(s.Port))

	return nil
}

// Send data
// send data UDP addr
func (s *UDPServer) Send(data []byte, addr *net.UDPAddr) {
	s.l.WriteToUDP(data, addr)
}

func (s *UDPServer) read() {
	defer s.l.Close()

	buf := make([]byte, 1024)
	for {
		n, addr, err := s.l.ReadFromUDP(buf)
		if err != nil {
			fmt.Println("read from udp err", err)
		}
		data := buf[0:n]
		go s.handleData(data, addr)
	}
}

func (s *UDPServer) handleData(data []byte, addr *net.UDPAddr) {
	devID := string(data[14:38])

	//devIP := strconv.Itoa(int(data[38]&0xff)) + "." + strconv.Itoa(int(data[39]&0xff)) + "." + strconv.Itoa(int(data[40]&0xff)) + "." + strconv.Itoa(int(data[41]&0xff))
	IP := addr.IP.String()

	/* bf := bytes.NewBuffer(data[62:66])
	var port int32
	binary.Read(bf, binary.LittleEndian, &port) */
	Port := addr.Port
	Mode := int(data[66])
	VoicePower := int(data[71])

	if ctx.Conf.TestMode {
		fmt.Println(devID)
		fmt.Println(IP)
		fmt.Println(Port)
		fmt.Println(Mode)
		fmt.Println(VoicePower)
	}

	ctx := GetCtx()
	dev := ctx.DevCache[devID]
	if dev == nil {
		ctx.DevCache[devID] = &Dev{
			DevID:      devID,
			IP:         IP,
			Port:       Port,
			Mode:       Mode,
			VoicePower: VoicePower,

			Ts:               0,
			Locked:           false,
			LockedByLevel:    0,
			LockedByUserID:   0,
			SpeechPacketTime: 0,

			CurrentTask: nil,

			Addr: addr,
		}
	} else {
		dev.DevID = devID
		dev.IP = IP
		dev.Port = Port
		dev.Mode = Mode
		dev.VoicePower = VoicePower

		dev.Ts = time.Now().Unix() / 1e6

		dev.Addr = addr
	}
}
